home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
Sherlock 2.0
/
Sherlock_DevLib
/
sl_macro.c
< prev
next >
Wrap
Text File
|
1996-04-06
|
14KB
|
754 lines
/*
Sherlock run-time macros.
source: sl_macro.c
started: November 4, 1993.
version:
April 5, 1996.
Changed computation of time in sl_ret.
February 5, 1996.
Added support for Symantec C.
November 15,1995
Added sl_unwatch.
January 7, 1994
*/
#include <LIBlib.h>
#include <sl.h>
#include <sl2.h>
#include <LIBenv.h>
#include <LIBmem.h>
#include <string.h>
#include <stdlib.h>
/*
All Sherlock macros will produce output if PRINT_EVERYTHING is #defined.
This logic was installed to test code generation in CC2.
*/
#if 0 && defined(applec)
#define PRINT_EVERYTHING
#endif
/*
Global variable set by sl_ret.
*/
long sl_theTicks;
sl_wnode * sl_wlist = NULL;
long sl_min_margin = 0;
long sl_margin_start = 0;
bool sl_time_flag = TRUE; /* TRUE: report time in exit macros. */
unsigned long sl_count = 0; /* The time returned by the interrupt timer. */
/*
Function prototypes of routines local to this file.
*/
static void sl_name_net (char *s);
static int sl_ret (char *s);
static int sl_visit (sl_node *np, int stat_flag, int entry_flag, char *s);
/*
Declare variables local to this file.
*/
static long sl_net; /* time Count . */
/*
Do not change the values of the following abbreviations.
*/
#define STAT_FLAG 1
#define NO_STAT_FLAG 0
#define ENTRY_FLAG 1
#define NO_ENTRY_FLAG 0
/*
Return a pointer to the statistics node for s.
*/
sl_node *
sl_find_name(char *s)
{
return sl_find(NULL, s);
}
/*
Output name and ticks.
*/
static void
sl_name_net(char *s)
{
epads(s, sl_nodots ? 20 : 0);
if (sl_time_flag) {
es(" (");
epadmsec(sl_net, sl_nodots ? 3 : 0);
es(" msec.) ");
}
else {
es(": ");
}
}
/*
Begin and end a section of overhead that does not contribute to statistics.
*/
void
sl_ovb(void)
{
register sl_snode * sp;
if (sl_stack == NULL) {
sl_abort(SL_ABORT_OVB);
}
if (sl_level-1 >= 0 && sl_level-1 < SL_MAX_STACK) {
sp = &sl_stack [sl_level-1];
if (sp -> overstart == 0) {
sp -> overstart = sl_ticks();
}
}
}
void
sl_ovx(void)
{
register sl_snode * sp;
long the_overhead;
if (sl_stack == NULL) {
sl_abort(SL_ABORT_OVX);
}
if (sl_level-1 >= 0 && sl_level-1 < SL_MAX_STACK) {
sp = &sl_stack [sl_level-1];
if (sp -> overstart != 0) {
the_overhead = sl_ticks() - sp -> overstart;
if (the_overhead < 0) {
the_overhead = 0;
}
sp -> overhead += the_overhead;
sp -> overstart = 0;
}
}
}
/*
TRACEPX macro.
*/
int
sl_pxtrace(char *s)
{
if (sl_ret(s)) {
sl_dots(sl_level);
sl_name_net(s);
return TRUE;
}
else {
return FALSE;
}
}
/*
Check for proper stack alignment using the entry name s.
Return TRUE if tracing is enabled.
*/
static bool watch_flag = FALSE;
static int
sl_ret(char *s)
{
register sl_snode * sp;
register sl_node * np;
register sl_node * np2;
register long raw_time = 0;
long time = 0;
char * s2 = s;
if (sl_troff || sl_stack == NULL) {
return FALSE;
}
#if 0 // defined(THINK_C) // Doesn't work on PowerPc
/* Set the minimum stack pointer. */
{
long margin = env_stackMargin();
if (sl_min_margin > margin) {
sl_min_margin = margin;
}
}
#endif
/* Check the watch list. */
if (sl_wlist) {
sl_watchall();
}
/*
Go to the previous level.
*/
if (sl_level <= 0) {
es("Sherlock underflow at "); es(s);
es("\nCheck for missing or misnamed exit macros.");
enl();
sl_dumpstk();
sl_exit();
}
else {
sl_level--;
}
sp = &sl_stack [sl_level];
np = sp -> node;
if (*s == '!' || *s == '-') {
s2 = s+1;
}
if (strcmp(np -> name, s2) != 0) {
ecnl();
es("sl_ret: Entry/Exit mismatch at exit point "); es(s); enl();
es("Expecting "); es(np -> name);
es(" got "); es(s2); enl();
es("Check for missing or misnamed exit macros.");
enl();
sl_dumpstk();
sl_exit();
}
if (sp -> overstart != 0) {
ecnl(); es("sl_ret: unterminated SL_OVB at exit point "); es(s); enl();
es("Check for missing SL_OVX macros.");
enl();
sl_dumpstk();
sl_exit();
}
/*
Update the regular statistics for the node at this level.
Set sl_net for sl_name_net.
*/
#ifdef SL_USE_MICROSECONDS
{
/*
Compute time = wide_stop_time - sp -> wide_start.
We assume that the interval between the start time and stop time
is be less than 2**32 microseconds, about 1 hour.
*/
UnsignedWide wide_stop_time;
Microseconds(&wide_stop_time);
time = wide_stop_time.lo - sp -> wide_start.lo;
}
#else
raw_time = sl_ticks();
time = raw_time - sp -> start;
#endif
if (time < 0) {
if (sl_warning) {
ecnl(); es("Negative time: "); es(sp -> node -> name);
es(" sl_level: "); eint(sl_level);
es(" raw time: "); ehex(raw_time);
es(" start: "); ehex(sp -> start); enl();
}
sl_neg_count++;
time = 0;
}
sl_theTicks = sl_net = time;
np -> time += (time - sp -> overhead);
sp -> overhead = 0L;
/*
Update the cumulative statistics for the previous node, if any.
Add the total time at this level to the *overhead* at the
previous level so only the time spent at that level is counted.
*/
if (sl_level > 0) {
sp = &sl_stack [sl_level-1];
sp -> overhead += time;
np2 = sp -> node;
np2 -> time2 += time;
}
/* Return TRUE if we should enable the macro. */
#ifdef PRINT_EVERYTHING
if (*s != '-') {
return TRUE;
}
#endif
if (s[0] == '!') {
return !((np -> trace) & SL_TRACE_BIT);
}
else if (s[0] == '-') {
return ((np -> trace) & SL_TRACE_BIT) && !((np -> trace) & SL_WILD_BIT);
}
else {
return (np -> trace) & SL_TRACE_BIT;
}
}
void
sl_unwatch(char * p, long length)
{
sl_wnode * p2 = NULL;
sl_wnode * p3 = NULL;
if (p == NULL || sl_wlist == NULL)
{
ecnl(); es("sl_unwatch: NULL p or sl_wlist!\n");
return;
}
if (p == sl_wlist -> wp)
{
p3 = sl_wlist;
sl_wlist = sl_wlist -> wnext;
}
else
{
p2 = sl_wlist;
p3 = sl_wlist -> wnext;
while (p3)
{
if (p == p3 -> wp)
{
p2 -> wnext = p3 -> wnext;
break;
}
p2 = p3;
p3 = p3 -> wnext;
}
}
if (p3)
{
if (length != p3 -> wlength)
{
ecnl(); es("sl_unmatch: mismatched lengths!\n");
abort();
}
es("Unwatching block: "); es(p3 -> wtag);
es(" at "); eptr(p3 -> wp);
es(" length: "); elong(p3 -> wlength); enl();
lib_free(p3 -> wsavep);
lib_free(p3);
}
}
/*
Visit node p.
Update tick statistics if stat_flag is TRUE.
Enter a section of timing code if entry_flag is TRUE.
Return TRUE if the node is currently enabled.
*/
static int
sl_visit(register sl_node *np, int stat_flag, int entry_flag, char * s)
{
register sl_snode * sp;
if (np == NULL || sl_stack == NULL) {
return FALSE;
}
#if 0 // defined(THINK_C) // Doesn't work on PowerPc
/* Set the minimum stack pointer. */
{
long margin = env_stackMargin();
if (sl_min_margin > margin) {
sl_min_margin = margin;
}
}
#endif
/* Check the watch list. */
if (sl_wlist) {
sl_watchall();
}
/* Update statistics if requested. */
if (stat_flag) {
np -> calls++;
}
/* Make an entry in the call stack for entry macros. */
if (entry_flag && sl_level < SL_MAX_STACK) {
/* Initialize the statistics. */
sp = &sl_stack[sl_level++];
sp -> node = np;
sp -> start = sl_ticks();
#ifdef SL_USE_MICROSECONDS
Microseconds(&sp -> wide_start);
#endif
sp -> overhead = 0L;
sp -> overstart = 0L;
sl_lmax = sl_level;
}
/* Return TRUE if macro should be enabled. */
#ifdef PRINT_EVERYTHING
if (s[0] != '-') {
return TRUE;
}
#endif
if (s[0] == '!') {
return !((np -> trace) & SL_TRACE_BIT);
}
else if (s[0] == '-') {
return ((np -> trace) & SL_TRACE_BIT) && !((np -> trace) & SL_WILD_BIT);
}
else {
return (np -> trace) & SL_TRACE_BIT;
}
}
/*
Add an item to the watch list.
*/
void
sl_watch(void * block_p, long block_length, char * tag)
{
/* Major bug! fixed 6/15/93: allocate sizeof(sl_wnode) bytes, not sl_node bytes! */
register sl_wnode * p = lib_calloc( (size_t) 1, sizeof(sl_wnode));
register long c;
p -> wnext = sl_wlist;
sl_wlist = p;
p -> wp = block_p;
p -> wlength = block_length;
p -> wsavep = lib_calloc( (size_t) 1, block_length);
p -> wtag = tag;
memmove(p -> wsavep, block_p, block_length);
ecnl();
es("Watching block: "); es(p -> wtag); es(" at "); eptr(p -> wp); es("... ");
if (p -> wlength > 10) {
enl();
}
if (p -> wlength < 20) {
for (c = 0; c < p -> wlength; c++) {
if ((c % 10) == 9) enl();
eblank(); epadhex(((p -> wsavep)[c]) & 0xff, 2); eblank();
}
}
ecnl();
}
/*
Watch all items on the watch list.
*/
void
sl_watchall(void)
{
register sl_wnode * p;
register long i;
for (p = sl_wlist; p; p = p -> wnext) {
if (memcmp(p -> wp, p -> wsavep, p -> wlength) != 0) {
ecnl();
es("Watch block: "); es(p -> wtag);
es(" changed. Base: "); eptr(p -> wp); enl();
if (p -> wlength < 20) {
es("Before..."); enl();
for (i = 0; i < p -> wlength; i++) {
if ((i % 10) == 9) enl();
eblank(); epadhex(((p -> wsavep)[i]) & 0xff, 2); eblank();
}
es("\nAfter..."); enl();
for (i = 0; i < p -> wlength; i++) {
if ((i % 10) == 9) enl();
eblank(); epadhex(((p -> wp)[i]) & 0xff, 2);
es((p -> wp[i] == p -> wsavep[i]) ? " " : "*");
}
}
else {
int linecount = 0;
long start, finish;
for(i = 0; p -> wp[i] == p -> wsavep[i]; i++) {
;
}
start = i;
for(i = start; i < p -> wlength; i++) {
if (p -> wp[i] != p -> wsavep[i]) {
finish = i;
}
}
finish++;
epads("offset:", 7); epads("before", 7); epads("after", 7); enl();
for (i = start; i < finish; i++) {
epadlong(i, 5); es(":");
eblank(); epadhex(((p -> wsavep)[i]) & 0xff, 2);
eblank(); epadhex(((p -> wp)[i]) & 0xff, 2);
es((p -> wp[i] == p -> wsavep[i]) ? " " : "*");
if ((++linecount % 4) == 3) {
enl();
}
}
}
ecnl();
memmove(p -> wsavep, p -> wp, p -> wlength);
sl_dumpstk(); ecnl();
abort();
}
}
}
/*
TICKX macro--Exit a nesting level and print s.
*/
void
sl_x(char *s)
{
if (sl_ret(s)) {
sl_dots(sl_level);
sl_name_net(s);
es("exits");
enl();
}
}
/*
STATX and TRACEX macros.
*/
int
sl_xtrace(char *s)
{
/* 4/9/93: Trace as with TICKB if sl_full_trace flag is on. */
if (sl_ret(s)) {
#ifdef PRINT_EVERYTHING
sl_dots(sl_level);
sl_name_net(s);
ecnl();
#else
if (sl_full_trace) {
sl_dots(sl_level);
sl_name_net(s);
ecnl();
}
#endif
return TRUE;
}
else {
return FALSE;
}
}
/*
STATB macro--Enter a new nesting level.
(Mark II Version).
*/
void
sl2bstat(sl_node **pp, char *s)
{
if (*pp == NULL) {
*pp = sl_find("STATB", s);
}
/* 4/9/93: Trace as with TICKB if sl_full_trace flag is on. */
if (sl_visit(*pp, STAT_FLAG, ENTRY_FLAG, s)) {
#ifdef PRINT_EVERYTHING
sl_dots(sl_level-1);
es(s); es(":"); enl();
#else
if (sl_full_trace) {
sl_dots(sl_level-1);
es(s); es(":"); enl();
}
#endif
}
}
/*
TICKB or ENTER macros--Enter a new nesting level.
(Mark II Version).
*/
void
sl2btick(sl_node **pp, char *s)
{
if (*pp == NULL) {
*pp = sl_find("TICKB", s);
}
if (sl_visit(*pp, STAT_FLAG, ENTRY_FLAG, s)) {
sl_dots(sl_level-1);
es(s); es(":"); enl();
}
}
/*
TRACEB macro--Enter a new nesting level.
(Mark II Version).
*/
int
sl2btrace(sl_node **pp, char *s)
{
if (*pp == NULL) {
*pp = sl_find("TRACEB", s);
}
/* 4/9/93: Trace as with TICKB if sl_full_trace flag is on. */
if (sl_visit(*pp, STAT_FLAG, ENTRY_FLAG, s)) {
#ifdef PRINT_EVERYTHING
sl_dots(sl_level-1);
es(s); es(":"); enl();
#else
if (sl_full_trace) {
sl_dots(sl_level-1);
es(s); es(":"); enl();
}
#endif
return TRUE;
}
else {
return FALSE;
}
}
/*
TICKN macro.
(Mark II Version.)
*/
void
sl2ntick(sl_node **pp, char * s)
{
if (*pp == NULL) {
*pp = sl_find("TICKN", s);
}
if (sl_visit(*pp, NO_STAT_FLAG, NO_ENTRY_FLAG, s)) {
sl_dots(sl_level-1);
es(s); es(":"); enl();
}
}
/*
TRACEN macro.
(Mark II Version.)
*/
int
sl2ntrace(sl_node **pp, char *s)
{
if (*pp == NULL) {
*pp = sl_find("TRACEN", s);
}
return sl_visit(*pp, NO_STAT_FLAG, NO_ENTRY_FLAG, s);
}
/*
TRACEPB and ENTER_TRACE macros--Enter a new nesting level.
(Mark II Version).
*/
int
sl2pbtrace(sl_node **pp, char *s)
{
if (*pp == NULL) {
*pp = sl_find("TRACEPB", s);
}
if (sl_visit(*pp, STAT_FLAG, ENTRY_FLAG, s)) {
sl_dots(sl_level-1);
es(s); es(": ");
return TRUE;
}
else {
return FALSE;
}
}
/*
TRACEPN macro.
(Mark II Version.)
*/
int
sl2pntrace(sl_node **pp, char *s)
{
if (*pp == NULL) {
*pp = sl_find("TRACEPN", s);
}
if (sl_visit(*pp, NO_STAT_FLAG, NO_ENTRY_FLAG, s)) {
sl_dots(sl_level-1);
es(s); es(": ");
return TRUE;
}
else {
return FALSE;
}
}
/*
TRACEP macro--TRACE with printing of tracepoint's name.
(Mark II Version.)
*/
int
sl2ptrace(sl_node **pp, char *s)
{
if (*pp == NULL) {
*pp = sl_find("TRACEP", s);
}
if (sl_visit(*pp, STAT_FLAG, NO_ENTRY_FLAG, s)) {
sl_dots(sl_level-1);
es(s); es(": ");
return TRUE;
}
else {
return FALSE;
}
}
/*
STAT macro--Update one statistic.
(Mark II Version.)
*/
void
sl2stat(sl_node **pp, char * s)
{
if (*pp == NULL) {
*pp = sl_find("STAT", s);
}
sl_visit(*pp, STAT_FLAG, NO_ENTRY_FLAG, s);
}
/*
TICK macro--Update one statistic and print tracepoint's name.
(Mark II Version.)
*/
void
sl2tick(sl_node **pp, char * s)
{
if (*pp == NULL) {
*pp = sl_find("TICK", s);
}
if (sl_visit(*pp, STAT_FLAG, NO_ENTRY_FLAG, s)) {
sl_dots(sl_level-1);
es(s); es(":"); enl();
}
}
/*
TRACE macro--Return TRUE if tracing s.
(Mark II Version.)
*/
int
sl2trace(sl_node **pp, char *s)
{
if (*pp == NULL) {
*pp = sl_find("TRACE", s);
}
return sl_visit(*pp, STAT_FLAG, NO_ENTRY_FLAG, s);
}